/******************************************************************************
 * Copyright (C) 2016 Wuhan Water Elephant Co.Ltd All Rights Reserved. 
 * 本软件为武汉水象科技有限公司开发研制。 未经本公司正式书面同意，其他任何个人、
 * 团体不得使用、复制、修改或发布本软件.
 *****************************************************************************/
package com.sxfq.loansupermarket.common.utils;

import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;

import com.sxfq.loansupermarket.common.constants.Constants;

/**
 * 
 * 
 * Module:
 * 
 * ControllerUtil.java
 * 
 * @author 毛恩奇
 * @since JDK 1.8
 * @version 1.0
 * @description: controller工具类
 */
public class ControllerUtil {
	// 第一个请求重复调用getCookieLoginToken会生成两个token，用threadLocal避免
	private static final ThreadLocal<String> loginThreadLocal = new ThreadLocal<String>();
	private static final ThreadLocal<String> businessThreadLocal = new ThreadLocal<String>();
	private static String cookiePath = "/";
	private static String cookieDomain;
	static {
		try {
			PropertiesConfiguration config = new PropertiesConfiguration("config/common.properties");
			if (StringUtils.isNotEmpty(config.getString("cookiePath"))) {
				cookiePath = config.getString("cookiePath");
			}
			if (StringUtils.isNotEmpty(config.getString("cookieDomain"))) {
				cookieDomain = config.getString("cookieDomain");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取cookie登录token
	 * 
	 * @param request
	 * @param response
	 * @return
	 */
	public static String getCookieLoginToken(HttpServletRequest request, HttpServletResponse response) {
		return getOrCreateCookieLoginToken(request, response, null);
	}

	/**
	 * 获取cookie登录token，获取不到则返回新的token
	 * 
	 * @param request
	 * @param response
	 * @param newLoginToken
	 *            cookie中没有则使用新的token，cookie中没有且传空则不生成新的token并返回null
	 * @return
	 */
	public static String getOrCreateCookieLoginToken(HttpServletRequest request, HttpServletResponse response,
			String newLoginToken) {
		Cookie[] cookies = request.getCookies();
		if (cookies != null && cookies.length > 0) {
			for (Cookie cookie : cookies) {
				String name = cookie.getName();
				if (Constants.SSO_COOKIE_ID.equals(name)) {
					return cookie.getValue();
				}
			}
		}
		if (StringUtils.isNotEmpty(newLoginToken)) {
			// 可能同一个request多次调用
			if (StringUtils.isNotEmpty(loginThreadLocal.get())) {
				String loginCookie = loginThreadLocal.get();
				writeLoginCookie(response, loginCookie);
				return loginCookie;
			}
			writeLoginCookie(response, newLoginToken);
			loginThreadLocal.set(newLoginToken);
			return newLoginToken;
		}
		return null;
	}

	/**
	 * 获取业务处理token
	 * 
	 * @param request
	 * @param response
	 * @return
	 */
	public static String getOrCreateBusinessToken(HttpServletRequest request, HttpServletResponse response) {
		Cookie[] cookies = request.getCookies();
		if (cookies != null && cookies.length > 0) {
			for (Cookie cookie : cookies) {
				String name = cookie.getName();
				if (Constants.BUSINESS_COOKIE_ID.equals(name)) {
					return cookie.getValue();
				}
			}
		} else if (StringUtils.isNotEmpty(businessThreadLocal.get())) {
			String loginCookie = businessThreadLocal.get();
			writeBusinessCookie(response, loginCookie);
			return loginCookie;
		}
		String uuid = UUID.randomUUID().toString().replace("-", "");
		writeBusinessCookie(response, uuid);
		businessThreadLocal.set(uuid);
		return uuid;
	}

	public static void writeCookie(HttpServletResponse response, String cookieKey, String cookieValue) {
		Cookie cookie = new Cookie(cookieKey, cookieValue);
		cookie.setMaxAge(-1);
		cookie.setPath(cookiePath);
		// 设置跨域 localhost == www.babasport.com www.jd.com search.jd.com
		// item.jd.com
		if (StringUtils.isNotEmpty(cookieDomain)) {
			cookie.setDomain(cookieDomain);
		}
		response.addCookie(cookie);
	}

	/**
	 * 
	 * @param response
	 * @param cookieValue
	 */
	private static void writeBusinessCookie(HttpServletResponse response, String cookieValue) {
		writeCookie(response, Constants.BUSINESS_COOKIE_ID, cookieValue);
	}

	/**
	 * 
	 * @param response
	 * @param cookieValue
	 */
	public static void writeLoginCookie(HttpServletResponse response, String cookieValue) {
		writeCookie(response, Constants.SSO_COOKIE_ID, cookieValue);
	}

	public static Cookie getCookie(Cookie[] cookies, String cookieName) {
		if (StringUtils.isNotEmpty(cookieName) && cookies != null && cookies.length > 0) {
			for (Cookie cookie : cookies) {
				String name = cookie.getName();
				if (cookieName.equals(name)) {
					return cookie;
				}
			}
		}
		return null;
	}

	public static void delCookie(HttpServletResponse response, String cookieKey) {
		Cookie newCookie = new Cookie(cookieKey, null);
		newCookie.setMaxAge(0);
		newCookie.setPath(cookiePath);
		response.addCookie(newCookie);
	}

	/**
	 * 获取请求参数Map
	 * 
	 * @param request
	 * @return
	 */
	public static Map<String, String> getRequestParamMap(HttpServletRequest request) {
		Map<String, String> paramMap = new HashMap<String, String>();
		if (request != null) {
			Enumeration<?> parameterNames = request.getParameterNames();
			while (parameterNames.hasMoreElements()) {
				String name = String.valueOf(parameterNames.nextElement());
				String value = "";
				if (!StringUtils.isEmpty(name)) {
					value = request.getParameter(name);
				}
				paramMap.put(name, value);
			}
		}
		return paramMap;
	}

	/**
	 * 判断是否ajax请求
	 * 
	 * @param request
	 * @return
	 */
	public static boolean isAjax(HttpServletRequest request) {
		boolean isAjax = false;
		if (request.getHeader("X-Requested-With") != null
				&& request.getHeader("X-Requested-With").equalsIgnoreCase("XMLHttpRequest")) {
			isAjax = true;
		}
		return isAjax;
	}

	/**
	 * 锁定同步请求
	 * 
	 * @param lockKey
	 * @param lockSeconds
	 * @return false：异常或已有正在处理请求；true：添加锁定数据成功，继续下一步
	 */
	public static boolean lockRequest(String lockKey, int lockSeconds) {
		Long lockKeyResult = RedisUtil.setNxAndEx(lockKey, DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"),
				lockSeconds);
		if (lockKeyResult == null || lockKeyResult <= 0L) {// redis异常或已有线程在处理
			return false;
		}
		return true;
	}
}